package com.dtu.distributed.controller;

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.InetAddress;
import java.net.MulticastSocket;
import java.rmi.AccessException;
import java.rmi.NotBoundException;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import java.rmi.server.UnicastRemoteObject;
import java.util.HashMap;
import java.util.Map.Entry;

import com.dtu.distributed.connection.AdminConnection;
import com.dtu.distributed.connection.AdminConnectionImpl;
import com.dtu.distributed.enums.Action;
import com.dtu.distributed.filereader.ReadNodeList;
import com.dtu.distributed.thread.AdminThread;
import com.dtu.distributed.thread.AdminElectionListenerThread;
import com.dtu.distributed.thread.TemperatureThread;

public class TempController {


	public static String myIpAddress;
	public static int rmiClientPort;
	public static int electionPort;
	public static int myadminTemperaturePort;

	public static String adminTemperatureIpAddress;
	public static int adminTemperaturePort = -1;

	public static String registryName;
	
	private static Registry registryClientConn;
	

	private static boolean admin = false;
	private static boolean binded = false;

	private static int count;
	private static double avg;

	private static AdminThread adminThread;
	private static TemperatureThread tempThread;
	private static AdminElectionListenerThread adminElectionListenerThread;


	public static synchronized void updateAvg(int temperature) {
		avg = (avg*count+temperature)/(count+1);
		count += 1;
	}

	public static synchronized void startTemperatureThread(){
		tempThread = new TemperatureThread();
		tempThread.start();
	}

	public static synchronized void stopTemperatureThread(){
		if (tempThread != null) {
			tempThread.interrupt();
		}
	}


	public static synchronized void startAdminElectionListenerThread(){
		adminElectionListenerThread = new AdminElectionListenerThread();
		adminElectionListenerThread.start();
	}

	public static synchronized void stopAdminElectionListenerThread(){
		if(adminElectionListenerThread != null){
		 adminElectionListenerThread.interrupt();
		}
	}
	public static synchronized AdminElectionListenerThread getAdminElectionListener(){
		return adminElectionListenerThread;
	}


	public static synchronized void makeAdmin(boolean makeAdmin){
		System.out.println("IN MAKE ADMIN - is admin: " + isAdmin() + ", make admin: " + makeAdmin);
		if (makeAdmin) {
			if (!isAdmin()) {
				admin = true;
				adminThread = new AdminThread();
				adminThread.start();	
			}
		} else {
			if (adminThread != null) {
				adminThread.interrupt();
			}
			admin = false;
		}
	}

	public static synchronized void bindClientConnection() {
		if (registryClientConn == null) {
			// Setup RMI
			
			if (!binded) {
				try {
					AdminConnectionImpl obj = new AdminConnectionImpl();
					AdminConnection stub = (AdminConnection) UnicastRemoteObject.exportObject(obj, 0);
									
					registryClientConn = LocateRegistry.getRegistry();
					registryClientConn.bind(registryName, stub);
					binded = true;
					System.out.println("Server is ready");
				} catch (Exception e) {
					System.err.println("Server exception: " + e.toString());
				}
			}
		}
	}

	public static synchronized void unbindClientConnection() {
		if (registryClientConn != null) {
			try {
				registryClientConn.unbind(registryName);
			} catch (AccessException e) {
				System.out.println("Server exception: " + e.toString());
			} catch (RemoteException e) {
				System.out.println("Server exception: " + e.toString());
			} catch (NotBoundException e) {
				System.out.println("Server exception: " + e.toString());
			}
		}
	}


	/*
	 * GETTERS & SETTERS
	 */

	public static synchronized double getAvg() {
		return avg;
	}

	public static synchronized boolean isAdmin() {
		return admin;
	}

	public static synchronized void setAdmin(boolean admin) {
		TempController.admin = admin;
	}
	
	public static synchronized boolean isBinded() {
		return binded;
	}

	public static synchronized void setBinded(boolean binded) {
		TempController.binded = binded;
	}

	public static synchronized void setNodelist(String path) {
		ReadNodeList reader= new ReadNodeList();
		BullyAlgorithmControlller.nodeList = reader.retrieveNodes(path);//set the node list in the bully controller
		for (Entry<Integer, String> entry : BullyAlgorithmControlller.nodeList.entrySet()) {//finds the nodes own identifier
			
			if(entry.getValue().trim().equals((myIpAddress + ":" + electionPort).trim())){
				BullyAlgorithmControlller.ownIdentifier=entry.getKey();
			}
			
			if(entry.getKey()>BullyAlgorithmControlller.maxIdentifier){
				BullyAlgorithmControlller.maxIdentifier=entry.getKey();
			}
		}
			
	}

}
